ref #8754: implement delete method for descriptiveDataSet
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptiveDataSetService.java
index c92c33cdad36c9138d8954ecc297f7e99a5a371f..ac28361c724123918ef635e82079ca51c83a7e93 100644 (file)
@@ -3,14 +3,15 @@ package eu.etaxonomy.cdm.api.service;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -18,7 +19,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
-import eu.etaxonomy.cdm.api.service.config.DescriptionAggregationConfiguration;
+import eu.etaxonomy.cdm.api.service.config.IdentifiableServiceConfiguratorImpl;
 import eu.etaxonomy.cdm.api.service.dto.RowWrapperDTO;
 import eu.etaxonomy.cdm.api.service.dto.SpecimenRowWrapperDTO;
 import eu.etaxonomy.cdm.api.service.dto.TaxonRowWrapperDTO;
@@ -27,36 +28,37 @@ import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
 import eu.etaxonomy.cdm.model.common.Language;
-import eu.etaxonomy.cdm.model.common.Marker;
-import eu.etaxonomy.cdm.model.common.MarkerType;
 import eu.etaxonomy.cdm.model.description.CategoricalData;
-import eu.etaxonomy.cdm.model.description.Character;
 import eu.etaxonomy.cdm.model.description.DescriptionBase;
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
+import eu.etaxonomy.cdm.model.description.DescriptionType;
 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
 import eu.etaxonomy.cdm.model.description.DescriptiveSystemRole;
 import eu.etaxonomy.cdm.model.description.Feature;
+import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
+import eu.etaxonomy.cdm.model.description.PolytomousKey;
 import eu.etaxonomy.cdm.model.description.QuantitativeData;
 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
-import eu.etaxonomy.cdm.model.description.StateData;
 import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
-import eu.etaxonomy.cdm.model.description.StatisticalMeasurementValue;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.description.TextData;
 import eu.etaxonomy.cdm.model.location.NamedArea;
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
-import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
 import eu.etaxonomy.cdm.model.taxon.Classification;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
+import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
+import eu.etaxonomy.cdm.persistence.dto.TermDto;
 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
+import eu.etaxonomy.cdm.strategy.generate.PolytomousKeyGenerator;
+import eu.etaxonomy.cdm.strategy.generate.PolytomousKeyGeneratorConfigurator;
 
 @Service
 @Transactional(readOnly=true)
@@ -73,16 +75,16 @@ public class DescriptiveDataSetService
     private ITaxonService taxonService;
 
     @Autowired
-    private IDescriptionService descriptionService;
+    private IPolytomousKeyService polytomousKeyService;
 
     @Autowired
-    private ITaxonNodeService taxonNodeService;
+    private IDefinedTermDao termDao;
 
     @Autowired
-    private IProgressMonitorService progressMonitorService;
+    private IDescriptionService descriptionService;
 
-    //FIXME: Use actual MarkerType for default descriptions when implemented #7957
-    private MarkerType MARKER_DEFAULT = MarkerType.TO_BE_CHECKED();
+    @Autowired
+    private ITaxonNodeService taxonNodeService;
 
        @Override
        @Autowired
@@ -108,7 +110,8 @@ public class DescriptiveDataSetService
     }
 
        @Override
-       public ArrayList<RowWrapperDTO> getRowWrapper(DescriptiveDataSet descriptiveDataSet, IProgressMonitor monitor) {
+       public ArrayList<RowWrapperDTO> getRowWrapper(UUID descriptiveDataSetUuid, IProgressMonitor monitor) {
+           DescriptiveDataSet descriptiveDataSet = load(descriptiveDataSetUuid);
            monitor.beginTask("Load row wrapper", descriptiveDataSet.getDescriptions().size());
            ArrayList<RowWrapperDTO> wrappers = new ArrayList<>();
            Set<DescriptionBase> descriptions = descriptiveDataSet.getDescriptions();
@@ -117,11 +120,17 @@ public class DescriptiveDataSetService
                 return new ArrayList<>();
             }
             RowWrapperDTO rowWrapper = null;
-            if(HibernateProxyHelper.isInstanceOf(description, TaxonDescription.class)){
+            // only viable descriptions are aggregated, literature or default descriptions
+            if(HibernateProxyHelper.isInstanceOf(description, TaxonDescription.class) &&
+                    (description.isAggregatedStructuredDescription()
+                            || description.getTypes().contains(DescriptionType.DEFAULT_VALUES_FOR_AGGREGATION)
+                            || description.getTypes().contains(DescriptionType.SECONDARY_DATA)
+                            )){
                 rowWrapper = createTaxonRowWrapper(description.getUuid(), descriptiveDataSet.getUuid());
             }
-            else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
-                rowWrapper = createSpecimenRowWrapper(HibernateProxyHelper.deproxy(description, SpecimenDescription.class), descriptiveDataSet);
+            else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)&&
+                    !description.getTypes().contains(DescriptionType.CLONE_FOR_SOURCE)){
+                rowWrapper = createSpecimenRowWrapper(HibernateProxyHelper.deproxy(description, SpecimenDescription.class), descriptiveDataSetUuid);
             }
             if(rowWrapper!=null){
                 wrappers.add(rowWrapper);
@@ -134,9 +143,19 @@ public class DescriptiveDataSetService
     @Override
     public Collection<SpecimenNodeWrapper> loadSpecimens(DescriptiveDataSet descriptiveDataSet){
         List<UUID> filteredNodes = findFilteredTaxonNodes(descriptiveDataSet);
+        if(filteredNodes.isEmpty()){
+            return Collections.EMPTY_SET;
+        }
         return occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(filteredNodes, null, null);
     }
 
+    @Override
+    public Collection<SpecimenNodeWrapper> loadSpecimens(UUID descriptiveDataSetUuid){
+        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
+        return loadSpecimens(dataSet);
+    }
+
+
     @Override
     public List<UUID> findFilteredTaxonNodes(DescriptiveDataSet descriptiveDataSet){
         TaxonNodeFilter filter = TaxonNodeFilter.NewRankInstance(descriptiveDataSet.getMinRank(), descriptiveDataSet.getMaxRank());
@@ -152,38 +171,39 @@ public class DescriptiveDataSetService
         return taxonNodeService.load(findFilteredTaxonNodes(descriptiveDataSet), propertyPaths);
     }
 
-    private TaxonNode findTaxonNodeForDescription(SpecimenDescription description, DescriptiveDataSet descriptiveDataSet){
-        SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
-        TaxonNode taxonNode = null;
-        //get taxon node
-        Set<TaxonNode> taxonSubtreeFilter = descriptiveDataSet.getTaxonSubtreeFilter();
-        for (TaxonNode node : taxonSubtreeFilter) {
-            //check for node
-            List<String> taxonNodePropertyPath = Arrays.asList("taxon", "taxon.descriptions", "taxon.descriptions.markers");
-            node = taxonNodeService.load(node.getId(), taxonNodePropertyPath);
-            taxonNode = findTaxonNodeForSpecimen(node, specimen);
-            if(taxonNode!=null){
-                break;
-            }
-            else{
-                //check for child nodes
-                List<TaxonNode> allChildren = taxonNodeService.loadChildNodesOfTaxonNode(node, taxonNodePropertyPath, true, true, null);
-                for (TaxonNode child : allChildren) {
-                    taxonNode = findTaxonNodeForSpecimen(child, specimen);
-                    if(taxonNode!=null){
-                        break;
-                    }
-                }
+    @Override
+    public TaxonDescription findDefaultDescription(UUID specimenDescriptionUuid, UUID dataSetUuid){
+        SpecimenDescription specimenDescription = (SpecimenDescription) descriptionService.load(specimenDescriptionUuid);
+        DescriptiveDataSet dataSet = load(dataSetUuid);
+        TaxonNode node = findTaxonNodeForDescription(specimenDescription, dataSet);
+        return recurseDefaultDescription(node, dataSet);
+    }
+
+    private TaxonDescription recurseDefaultDescription(TaxonNode node, DescriptiveDataSet dataSet){
+        TaxonDescription defaultDescription = null;
+        if(node!=null && node.getTaxon()!=null){
+            defaultDescription = findTaxonDescriptionByDescriptionType(dataSet, node.getTaxon(), DescriptionType.DEFAULT_VALUES_FOR_AGGREGATION);
+            if(defaultDescription==null && node.getParent()!=null){
+                defaultDescription = recurseDefaultDescription(node.getParent(), dataSet);
             }
         }
-        return taxonNode;
+        return defaultDescription;
     }
 
-    private TaxonNode findTaxonNodeForSpecimen(TaxonNode taxonNode, SpecimenOrObservationBase<?> specimen){
-        Collection<SpecimenNodeWrapper> nodeWrapper = occurrenceService.listUuidAndTitleCacheByAssociatedTaxon(Arrays.asList(taxonNode.getUuid()), null, null);
-        for (SpecimenNodeWrapper specimenNodeWrapper : nodeWrapper) {
-            if(specimenNodeWrapper.getUuidAndTitleCache().getId().equals(specimen.getId())){
-                return taxonNode;
+    private TaxonNode findTaxonNodeForDescription(SpecimenDescription description, DescriptiveDataSet descriptiveDataSet){
+        SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
+        //get taxon node
+
+        Set<IndividualsAssociation> associations = (Set<IndividualsAssociation>)descriptiveDataSet.getDescriptions()
+                .stream()
+                .flatMap(desc->desc.getElements().stream())// put all description element in one stream
+                .filter(element->element instanceof IndividualsAssociation)
+                .map(ia->(IndividualsAssociation)ia)
+                .collect(Collectors.toSet());
+        Classification classification = descriptiveDataSet.getTaxonSubtreeFilter().iterator().next().getClassification();
+        for (IndividualsAssociation individualsAssociation : associations) {
+            if(individualsAssociation.getAssociatedSpecimenOrObservation().equals(specimen)){
+                return ((TaxonDescription) individualsAssociation.getInDescription()).getTaxon().getTaxonNode(classification);
             }
         }
         return null;
@@ -208,10 +228,71 @@ public class DescriptiveDataSetService
     }
 
     @Override
-    public SpecimenRowWrapperDTO createSpecimenRowWrapper(SpecimenDescription description, DescriptiveDataSet descriptiveDataSet){
-           SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
-           //supplemental information
-           TaxonNode taxonNode = findTaxonNodeForDescription(description, descriptiveDataSet);
+    @Transactional(readOnly=false)
+    public UpdateResult addRowWrapperToDataset(Collection<SpecimenNodeWrapper> wrappers, UUID datasetUuid){
+        UpdateResult result = new UpdateResult();
+        DescriptiveDataSet dataSet = load(datasetUuid);
+        result.setCdmEntity(dataSet);
+
+        List<UUID> taxonUuids = wrappers.stream().map(wrapper->wrapper.getTaxonNode().getTaxon().getUuid()).collect(Collectors.toList());
+        List<TaxonBase> taxa = taxonService.load(taxonUuids, Arrays.asList(new String[]{"descriptions"}));
+
+        for (SpecimenNodeWrapper wrapper : wrappers) {
+            Optional<TaxonBase> findAny = taxa.stream().filter(taxon->taxon.getUuid().equals(wrapper.getTaxonNode().getTaxon().getUuid())).findAny();
+            if(!findAny.isPresent()){
+                result.addException(new IllegalArgumentException("Could not create wrapper for "+wrapper.getUuidAndTitleCache().getTitleCache()));
+                continue;
+            }
+            Taxon taxon = (Taxon) findAny.get();
+            UUID taxonDescriptionUuid = wrapper.getTaxonDescriptionUuid();
+            TaxonDescription taxonDescription = null;
+            if(taxonDescriptionUuid!=null){
+                taxonDescription = (TaxonDescription) descriptionService.load(taxonDescriptionUuid);
+            }
+            if(taxonDescription==null){
+                Optional<TaxonDescription> associationDescriptionOptional = taxon.getDescriptions().stream()
+                        .filter(desc->desc.getTypes().contains(DescriptionType.INDIVIDUALS_ASSOCIATION))
+                        .findFirst();
+                if(!associationDescriptionOptional.isPresent()){
+                    taxonDescription = TaxonDescription.NewInstance(taxon);
+                }
+                else{
+                    taxonDescription = associationDescriptionOptional.get();
+                }
+
+                SpecimenOrObservationBase specimen = occurrenceService.load(wrapper.getUuidAndTitleCache().getUuid());
+                IndividualsAssociation association = IndividualsAssociation.NewInstance(specimen);
+                taxonDescription.addElement(association);
+                taxonService.saveOrUpdate(taxon);
+                result.addUpdatedObject(taxon);
+            }
+            SpecimenDescription specimenDescription = findSpecimenDescription(datasetUuid, wrapper.getUuidAndTitleCache().getUuid(), true);
+            SpecimenRowWrapperDTO rowWrapper = createSpecimenRowWrapper(specimenDescription, wrapper.getTaxonNode().getUuid(), datasetUuid);
+            if(rowWrapper==null){
+                result.addException(new IllegalArgumentException("Could not create wrapper for "+specimenDescription));
+                continue;
+            }
+            //add specimen description to data set
+            rowWrapper.getDescription().addDescriptiveDataSet(dataSet);
+            //add taxon description with IndividualsAssociation to the specimen to data set
+            taxonDescription.addDescriptiveDataSet(dataSet);
+
+            result.addUpdatedObject(rowWrapper.getDescription());
+            result.addUpdatedObject(taxonDescription);
+        }
+        saveOrUpdate(dataSet);
+        return result;
+    }
+
+    private SpecimenRowWrapperDTO createSpecimenRowWrapper(SpecimenDescription description, UUID taxonNodeUuid,
+            UUID datasetUuid) {
+        TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid);
+        DescriptiveDataSet descriptiveDataSet = load(datasetUuid);
+        SpecimenOrObservationBase specimen = description.getDescribedSpecimenOrObservation();
+        //supplemental information
+        if(taxonNode==null){
+            taxonNode = findTaxonNodeForDescription(description, descriptiveDataSet);
+        }
         FieldUnit fieldUnit = null;
         String identifier = null;
         NamedArea country = null;
@@ -242,11 +323,17 @@ public class DescriptiveDataSetService
             country = fieldUnit.getGatheringEvent().getCountry();
         }
         //get default taxon description
-        TaxonDescription defaultTaxonDescription = findTaxonDescriptionByMarkerType(descriptiveDataSet.getUuid(),
-                taxonNode.getUuid(), MARKER_DEFAULT);
+        TaxonDescription defaultTaxonDescription = findDefaultDescription(description.getUuid(), descriptiveDataSet.getUuid());
         TaxonRowWrapperDTO taxonRowWrapper = defaultTaxonDescription != null
                 ? createTaxonRowWrapper(defaultTaxonDescription.getUuid(), descriptiveDataSet.getUuid()) : null;
-        return new SpecimenRowWrapperDTO(description, new TaxonNodeDto(taxonNode), fieldUnit, identifier, country);
+        SpecimenRowWrapperDTO specimenRowWrapperDTO = new SpecimenRowWrapperDTO(description, new TaxonNodeDto(taxonNode), fieldUnit, identifier, country);
+        specimenRowWrapperDTO.setDefaultDescription(taxonRowWrapper);
+        return specimenRowWrapperDTO;
+    }
+
+    @Override
+    public SpecimenRowWrapperDTO createSpecimenRowWrapper(SpecimenDescription description, UUID descriptiveDataSetUuid){
+        return createSpecimenRowWrapper(description, null, descriptiveDataSetUuid);
        }
 
     @Override
@@ -259,12 +346,10 @@ public class DescriptiveDataSetService
         return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
     }
 
-    private TaxonDescription findTaxonDescriptionByMarkerType(DescriptiveDataSet dataSet, Taxon taxon, MarkerType markerType){
-        Set<DescriptionBase> dataSetDescriptions = dataSet.getDescriptions();
-        //filter by DEFAULT descriptions
+    private TaxonDescription findTaxonDescriptionByDescriptionType(DescriptiveDataSet dataSet, Taxon taxon, DescriptionType descriptionType){
         Optional<TaxonDescription> first = taxon.getDescriptions().stream()
-                .filter(desc -> desc.getMarkers().stream().anyMatch(marker -> marker.getMarkerType().equals(markerType)))
-                .filter(defaultDescription->dataSetDescriptions.contains(defaultDescription))
+                .filter(desc -> desc.getTypes().stream().anyMatch(type -> type.equals(descriptionType)))
+                .filter(desc -> dataSet.getDescriptions().contains(desc))
                 .findFirst();
         if(first.isPresent()){
             return HibernateProxyHelper.deproxy(descriptionService.load(first.get().getUuid(),
@@ -274,185 +359,36 @@ public class DescriptiveDataSetService
     }
 
     @Override
-    public TaxonDescription findTaxonDescriptionByMarkerType(UUID dataSetUuid, UUID taxonNodeUuid, MarkerType markerType){
+    public TaxonDescription findTaxonDescriptionByDescriptionType(UUID dataSetUuid, UUID taxonNodeUuid, DescriptionType descriptionType){
         DescriptiveDataSet dataSet = load(dataSetUuid);
         TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid);
-        return findTaxonDescriptionByMarkerType(dataSet, taxonNode.getTaxon(), markerType);
+        return findTaxonDescriptionByDescriptionType(dataSet, taxonNode.getTaxon(), descriptionType);
     }
 
     @Override
     @Transactional(readOnly=false)
-    public UpdateResult aggregate(UUID descriptiveDataSetUuid, DescriptionAggregationConfiguration config, IProgressMonitor monitor) {
-        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
-        Set<DescriptionBase> descriptions = dataSet.getDescriptions();
-
-        monitor.beginTask("Aggregate data set", descriptions.size()*2);
-
+    public UpdateResult generatePolytomousKey(UUID descriptiveDataSetUuid, UUID taxonUuid) {
         UpdateResult result = new UpdateResult();
 
-        // sort descriptions by taxa
-        Map<TaxonNode, Set<UUID>> taxonNodeToSpecimenDescriptionMap = new HashMap<>();
-        for (DescriptionBase descriptionBase : descriptions) {
-            if(monitor.isCanceled()){
-                result.setAbort();
-                return result;
-            }
-
-            if(descriptionBase instanceof SpecimenDescription){
-                SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(descriptionBase, SpecimenDescription.class);
-                TaxonNode taxonNode = findTaxonNodeForDescription(specimenDescription, dataSet);
-                if(taxonNode!=null){
-                    addDescriptionToTaxonNodeMap(specimenDescription.getUuid(), taxonNode, taxonNodeToSpecimenDescriptionMap);
-                }
-            }
-            monitor.worked(1);
+        PolytomousKeyGeneratorConfigurator keyConfig = new PolytomousKeyGeneratorConfigurator();
+        DescriptiveDataSet descriptiveDataSet = load(descriptiveDataSetUuid);
+        keyConfig.setDataSet(descriptiveDataSet);
+        PolytomousKey key = new PolytomousKeyGenerator().invoke(keyConfig);
+        IdentifiableServiceConfiguratorImpl<PolytomousKey> serviceConfig= new IdentifiableServiceConfiguratorImpl<>();
+        serviceConfig.setTitleSearchString(descriptiveDataSet.getTitleCache());
+        List<PolytomousKey> list = polytomousKeyService.findByTitle(serviceConfig).getRecords();
+        if(list!=null){
+            list.forEach(polytomousKey->polytomousKeyService.delete(polytomousKey));
         }
-        if(config.isRecursiveAggregation()){
-            propagateDescriptionsToParentNodes(dataSet, taxonNodeToSpecimenDescriptionMap);
-        }
-        // aggregate per taxa
-        for (Entry<TaxonNode, Set<UUID>> entry: taxonNodeToSpecimenDescriptionMap.entrySet()) {
-            if(monitor.isCanceled()){
-                result.setAbort();
-                return result;
-            }
-            UUID taxonUuid = entry.getKey().getTaxon().getUuid();
-            Set<UUID> specimenDescriptionUuids = entry.getValue();
-            result.includeResult(aggregateDescription(taxonUuid , specimenDescriptionUuids, descriptiveDataSetUuid));
-            monitor.worked(1);
-        }
-        monitor.done();
-        return result;
-    }
+        key.setTitleCache(descriptiveDataSet.getTitleCache(), true);
 
-    private void addDescriptionToTaxonNodeMap(UUID descriptionUuid, TaxonNode taxonNode, Map<TaxonNode, Set<UUID>> taxonNodeToSpecimenDescriptionMap){
-        Set<UUID> specimenDescriptionUuids = taxonNodeToSpecimenDescriptionMap.get(taxonNode);
-        if(specimenDescriptionUuids==null){
-            specimenDescriptionUuids = new HashSet<>();
-        }
-        specimenDescriptionUuids.add(descriptionUuid);
-        taxonNodeToSpecimenDescriptionMap.put(taxonNode, specimenDescriptionUuids);
-    }
-
-    private void propagateDescriptionsToParentNodes(DescriptiveDataSet dataSet, Map<TaxonNode, Set<UUID>> taxonNodeToSpecimenDescriptionMap){
-        Map<TaxonNode, Set<UUID>> parentMap = new HashMap<>();
-        for (Entry<TaxonNode, Set<UUID>> entry: taxonNodeToSpecimenDescriptionMap.entrySet()) {
-            Set<UUID> descriptionUuids = entry.getValue();
-            TaxonNode node = entry.getKey();
-            TaxonNode parentNode = node.getParent();
-            while(parentNode!=null && isTaxonNodeInDescriptiveDataSet(parentNode, dataSet)){
-                for (UUID uuid : descriptionUuids) {
-                    addDescriptionToTaxonNodeMap(uuid, node.getParent(), parentMap);
-                }
-                parentNode = parentNode.getParent();
-            }
-        }
-        // merge parent map
-        for (Entry<TaxonNode, Set<UUID>> entry: parentMap.entrySet()) {
-            Set<UUID> descriptionUuids = entry.getValue();
-            TaxonNode node = entry.getKey();
-            for (UUID uuid : descriptionUuids) {
-                addDescriptionToTaxonNodeMap(uuid, node, taxonNodeToSpecimenDescriptionMap);
-            }
-        }
-    }
-
-    private boolean isTaxonNodeInDescriptiveDataSet(TaxonNode taxonNode, DescriptiveDataSet dataSet){
-        Set<TaxonNode> taxonSubtreeFilter = dataSet.getTaxonSubtreeFilter();
-        for (TaxonNode datasetNode : taxonSubtreeFilter) {
-            if(datasetNode.getUuid().equals(taxonNode.getUuid())){
-                return true;
-            }
-            List<TaxonNode> allChildren = taxonNodeService.loadChildNodesOfTaxonNode(datasetNode, null, true, true, null);
-            for (TaxonNode childNode : allChildren) {
-                if(childNode.getUuid().equals(taxonNode.getUuid())){
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @SuppressWarnings("unchecked")
-    private UpdateResult aggregateDescription(UUID taxonUuid, Set<UUID> descriptionUuids, UUID descriptiveDataSetUuid) {
-        UpdateResult result = new UpdateResult();
-
-        TaxonBase taxonBase = taxonService.load(taxonUuid);
-        if(!(taxonBase instanceof Taxon)){
-            result.addException(new ClassCastException("The given taxonUUID does not belong to a taxon"));
-            result.setError();
-            return result;
-        }
-        Taxon taxon = (Taxon)taxonBase;
-        List<DescriptionBase> descriptions = descriptionService.load(new ArrayList<>(descriptionUuids), null);
-        Map<Character, List<DescriptionElementBase>> featureToElementMap = new HashMap<>();
-
-        DescriptiveDataSet dataSet = load(descriptiveDataSetUuid);
-        if(dataSet==null){
-            result.addException(new IllegalArgumentException("Could not find data set for uuid "+descriptiveDataSetUuid));
-            result.setAbort();
-            return result;
-        }
-
-        //extract all character description elements
-        descriptions.forEach(description->{
-            description.getElements()
-            .stream()
-            //filter out elements that do not have a Character as Feature
-            .filter(element->HibernateProxyHelper.isInstanceOf(((DescriptionElementBase)element).getFeature(), Character.class))
-            .forEach(ele->{
-                DescriptionElementBase descriptionElement = (DescriptionElementBase)ele;
-                List<DescriptionElementBase> list = featureToElementMap.get(descriptionElement.getFeature());
-                if(list==null){
-                    list = new ArrayList<>();
-                }
-                list.add(descriptionElement);
-                featureToElementMap.put(HibernateProxyHelper.deproxy(descriptionElement.getFeature(), Character.class), list);
-            });
-        });
+        Taxon taxon = (Taxon) taxonService.load(taxonUuid);
+        key.addTaxonomicScope(taxon);
 
-        // delete all aggregation description of this dataset (MarkerType.COMPUTED)
-        dataSet.getDescriptions().stream()
-        .filter(aggDesc->aggDesc instanceof TaxonDescription)
-        .filter(desc -> desc.getMarkers().stream().anyMatch(marker -> marker.getMarkerType().equals(MarkerType.COMPUTED())))
-        .map(aggDesc->(TaxonDescription)aggDesc)
-        .forEach(aggregatedDescription->{
-            removeDescription(aggregatedDescription.getUuid(), descriptiveDataSetUuid);
-            taxon.removeDescription(aggregatedDescription);
-            descriptionService.delete(aggregatedDescription);
-        });
+        polytomousKeyService.saveOrUpdate(key);
 
-        // create new aggregation
-        TaxonDescription description = TaxonDescription.NewInstance(taxon);
-        description.setTitleCache("[Aggregation] "+dataSet.getTitleCache(), true);
-        description.addMarker(Marker.NewInstance(MarkerType.COMPUTED(), true));
-        IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.Aggregation);
-        description.addSource(source);
-        description.addDescriptiveDataSet(dataSet);
-
-        featureToElementMap.forEach((feature, elements)->{
-            //aggregate categorical data
-            if(feature.isSupportsCategoricalData()){
-                CategoricalData aggregate = CategoricalData.NewInstance(feature);
-                elements.stream()
-                .filter(element->element instanceof CategoricalData)
-                .forEach(categoricalData->((CategoricalData)categoricalData).getStateData()
-                        .forEach(stateData->aggregate.addStateData((StateData) stateData.clone())));
-                description.addElement(aggregate);
-            }
-            //aggregate quantitative data
-            else if(feature.isSupportsQuantitativeData()){
-                QuantitativeData aggregate = QuantitativeData.NewInstance(feature);
-                elements.stream()
-                .filter(element->element instanceof QuantitativeData)
-                .forEach(categoricalData->((QuantitativeData)categoricalData).getStatisticalValues()
-                        .forEach(statisticalValue->aggregate.addStatisticalValue((StatisticalMeasurementValue) statisticalValue.clone())));
-                description.addElement(aggregate);
-            }
-        });
+        result.setCdmEntity(key);
         result.addUpdatedObject(taxon);
-        result.addUpdatedObject(description);
-
         return result;
     }
 
@@ -468,32 +404,62 @@ public class DescriptiveDataSetService
         else{
             boolean success = dataSet.removeDescription(descriptionBase);
             result.addDeletedObject(descriptionBase);
+            // remove taxon description with IndividualsAssociation from data set
+            if(descriptionBase instanceof SpecimenDescription){
+                @SuppressWarnings("cast")
+                Set<IndividualsAssociation> associations = (Set<IndividualsAssociation>)dataSet.getDescriptions()
+                        .stream()
+                        .flatMap(desc->desc.getElements().stream())// put all description element in one stream
+                        .filter(element->element instanceof IndividualsAssociation)
+                        .map(ia->(IndividualsAssociation)ia)
+                        .collect(Collectors.toSet());
+                Classification classification = dataSet.getTaxonSubtreeFilter().iterator().next().getClassification();
+                for (IndividualsAssociation individualsAssociation : associations) {
+                    if(individualsAssociation.getAssociatedSpecimenOrObservation().equals(descriptionBase.getDescribedSpecimenOrObservation())){
+                        dataSet.removeDescription(individualsAssociation.getInDescription());
+                        result.addDeletedObject(individualsAssociation.getInDescription());
+                    }
+                }
+            }
             result.addUpdatedObject(dataSet);
             result.setStatus(success?Status.OK:Status.ERROR);
         }
         return result;
     }
 
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult delete(UUID datasetUuid){
+        DescriptiveDataSet dataSet = dao.load(datasetUuid);
+        DeleteResult result = new DeleteResult();
+        if (!dataSet.getDescriptions().isEmpty()){
+            Set<DescriptionBase> descriptions = new HashSet();;
+            for (DescriptionBase desc: dataSet.getDescriptions()){
+                descriptions.add(desc);
+            }
+            DeleteResult descriptionResult;
+            for (DescriptionBase desc: descriptions){
+                dataSet.removeDescription(desc);
+                descriptionResult = descriptionService.deleteDescription(desc);
+                result.includeResult(descriptionResult);
+            }
+
+
+        }
+        dao.delete(dataSet);
+        result.addDeletedObject(dataSet);
+        return result;
+    }
+
     @Override
     @Transactional(readOnly=false)
-    public TaxonRowWrapperDTO createTaxonDescription(UUID dataSetUuid, UUID taxonNodeUuid, MarkerType markerType, boolean markerFlag){
+    public TaxonRowWrapperDTO createTaxonDescription(UUID dataSetUuid, UUID taxonNodeUuid, DescriptionType descriptionType){
         DescriptiveDataSet dataSet = load(dataSetUuid);
         TaxonNode taxonNode = taxonNodeService.load(taxonNodeUuid, Arrays.asList("taxon"));
         TaxonDescription newTaxonDescription = TaxonDescription.NewInstance(taxonNode.getTaxon());
-        String tag = "";
-        if(markerFlag){
-            //FIXME: Add specific MarkerTypes to enum (see #7957)
-            if(markerType.equals(MARKER_DEFAULT)){
-                tag = "[Default]";
-            }
-            else if(markerType.equals(MarkerType.IN_BIBLIOGRAPHY())){
-                tag = "[Literature]";
-            }
-        }
-        newTaxonDescription.setTitleCache(tag+" "+dataSet.getLabel()+": "+newTaxonDescription.generateTitle(), true); //$NON-NLS-2$
-        if(markerType!=null){
-            newTaxonDescription.addMarker(Marker.NewInstance(markerType, markerFlag));
-        }
+        newTaxonDescription.setTitleCache(dataSet.getLabel()+": "+newTaxonDescription.generateTitle(), true); //$NON-NLS-2$
+        newTaxonDescription.getTypes().add(descriptionType);
+
         dataSet.getDescriptiveSystem().getDistinctTerms().forEach(wsFeature->{
             if(wsFeature.isSupportsCategoricalData()){
                 newTaxonDescription.addElement(CategoricalData.NewInstance(wsFeature));
@@ -507,6 +473,11 @@ public class DescriptiveDataSetService
         return createTaxonRowWrapper(newTaxonDescription.getUuid(), dataSet.getUuid());
     }
 
+    @Override
+    public List<TermDto> getSupportedStatesForFeature(UUID featureUuid){
+        return termDao.getSupportedStatesForFeature(featureUuid);
+    }
+
     @Override
     @Transactional(readOnly=false)
     public SpecimenDescription findSpecimenDescription(UUID descriptiveDataSetUuid, UUID specimenUuid, boolean addDatasetSource){
@@ -529,7 +500,7 @@ public class DescriptiveDataSetService
             for (DescriptionElementBase specimenDescriptionElement : specimenDescription.getElements()) {
                 Feature feature = specimenDescriptionElement.getFeature();
                 specimenDescriptionFeatures.add(feature);
-                if(datasetFeatures.contains(feature)){
+                if(datasetFeatures.contains(feature) && RowWrapperDTO.hasData(specimenDescriptionElement)){
                     matchingDescriptionElements.add(specimenDescriptionElement);
                 }
             }
@@ -595,24 +566,6 @@ public class DescriptiveDataSetService
             }
         }
 
-        //add all remaining description elements to the new description
-        for(Feature wsFeature:datasetFeatures){
-            boolean featureFound = false;
-            for(DescriptionElementBase element:newDesription.getElements()){
-                if(element.getFeature().equals(wsFeature)){
-                    featureFound = true;
-                    break;
-                }
-            }
-            if(!featureFound){
-                if(wsFeature.isSupportsCategoricalData()){
-                    newDesription.addElement(CategoricalData.NewInstance(wsFeature));
-                }
-                else if(wsFeature.isSupportsQuantitativeData()){
-                    newDesription.addElement(QuantitativeData.NewInstance(wsFeature));
-                }
-            }
-        }
         //add sources of data set
         if(addDatasetSource){
             dataSet.getSources().forEach(source->{
@@ -804,6 +757,8 @@ public class DescriptiveDataSetService
             return DescriptiveDataSetService.this;
         }
 
+
+
     }
 
 }