fix merge description into another description
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonNodeServiceImpl.java
index 59eb5ee2ee276a67156d06cc2587087c0bdd665b..0dd73bc67ab566c770c8f89088c7e4c5e6111f8a 100644 (file)
@@ -11,6 +11,7 @@
 package eu.etaxonomy.cdm.api.service;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -23,22 +24,25 @@ import org.springframework.beans.factory.annotation.Autowired;
 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.NodeDeletionConfigurator.ChildHandling;
 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
 import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator;
-import eu.etaxonomy.cdm.api.service.config.TaxonNodeDeletionConfigurator.ChildHandling;
+import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
 import eu.etaxonomy.cdm.model.reference.Reference;
 import eu.etaxonomy.cdm.model.taxon.Classification;
-import eu.etaxonomy.cdm.model.taxon.ITaxonNodeComparator;
-import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
 import eu.etaxonomy.cdm.model.taxon.Synonym;
 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonNaturalComparator;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
+import eu.etaxonomy.cdm.model.taxon.TaxonNodeByNameComparator;
+import eu.etaxonomy.cdm.model.taxon.TaxonNodeByRankAndNameComparator;
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
 import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
@@ -56,7 +60,7 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
     @Autowired
     private IBeanInitializer defaultBeanInitializer;
 
-    private Comparator<? super TaxonNode> taxonNodeComparator;
+    private final Comparator<? super TaxonNode> taxonNodeComparator = new TaxonNodeByNameComparator();
 
     @Autowired
     private ITaxonService taxonService;
@@ -64,14 +68,11 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
     @Autowired
     private IClassificationService classService;
 
-    @Autowired
-    public void setTaxonNodeComparator(ITaxonNodeComparator<? super TaxonNode> taxonNodeComparator){
-        this.taxonNodeComparator = (Comparator<? super TaxonNode>) taxonNodeComparator;
-    }
+
 
     @Override
     public List<TaxonNode> loadChildNodesOfTaxonNode(TaxonNode taxonNode,
-            List<String> propertyPaths, boolean recursive, boolean sorted) {
+            List<String> propertyPaths, boolean recursive, NodeSortMode sortMode) {
         taxonNode = dao.load(taxonNode.getUuid());
         List<TaxonNode> childNodes;
         if (recursive == true){
@@ -79,28 +80,31 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
         }else{
                childNodes = new ArrayList<TaxonNode>(taxonNode.getChildNodes());
         }
-        if (sorted){
-               Collections.sort(childNodes, taxonNodeComparator);
+        if (sortMode != null){
+            Comparator<TaxonNode> comparator = null;
+            if (sortMode.equals(NodeSortMode.NaturalOrder)){
+                comparator = new TaxonNaturalComparator();
+            } else if (sortMode.equals(NodeSortMode.AlphabeticalOrder)){
+               comparator = new TaxonNodeByNameComparator();
+            } else if (sortMode.equals(NodeSortMode.RankAndAlphabeticalOrder)){
+               comparator = new TaxonNodeByRankAndNameComparator();
+            }
+               Collections.sort(childNodes, comparator);
         }
         defaultBeanInitializer.initializeAll(childNodes, propertyPaths);
         return childNodes;
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
-     */
     @Override
     @Autowired
     protected void setDao(ITaxonNodeDao dao) {
         this.dao = dao;
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.ITaxonService#makeTaxonSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Taxon)
-     */
     @Override
     @Transactional(readOnly = false)
-    public Synonym makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode, SynonymRelationshipType synonymRelationshipType, Reference citation, String citationMicroReference)  {
+    public DeleteResult makeTaxonNodeASynonymOfAnotherTaxonNode(TaxonNode oldTaxonNode, TaxonNode newAcceptedTaxonNode, SynonymRelationshipType synonymRelationshipType, Reference citation, String citationMicroReference)  {
+
 
         // TODO at the moment this method only moves synonym-, concept relations and descriptions to the new accepted taxon
         // in a future version we also want to move cdm data like annotations, marker, so., but we will need a policy for that
@@ -113,14 +117,14 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
         }
 
 
-
+        Classification classification = oldTaxonNode.getClassification();
         Taxon oldTaxon = (Taxon) HibernateProxyHelper.deproxy(oldTaxonNode.getTaxon());
-        Taxon newAcceptedTaxon = (Taxon) HibernateProxyHelper.deproxy(newAcceptedTaxonNode.getTaxon());
-
+        Taxon newAcceptedTaxon = (Taxon)this.taxonService.load(newAcceptedTaxonNode.getTaxon().getUuid());
         // Move oldTaxon to newTaxon
         //TaxonNameBase<?,?> synonymName = oldTaxon.getName();
         TaxonNameBase<?,?> synonymName = (TaxonNameBase)HibernateProxyHelper.deproxy(oldTaxon.getName());
         HomotypicalGroup group = synonymName.getHomotypicalGroup();
+        group = HibernateProxyHelper.deproxy(group, HomotypicalGroup.class);
         if (synonymRelationshipType == null){
             if (synonymName.isHomotypic(newAcceptedTaxon.getName())){
                 synonymRelationshipType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
@@ -131,8 +135,8 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
 
         //set homotypic group
         HomotypicalGroup newAcceptedTaxonHomotypicalgroup = newAcceptedTaxon.getHomotypicGroup();
-       HibernateProxyHelper.deproxy(newAcceptedTaxonHomotypicalgroup);
-       HibernateProxyHelper.deproxy(newAcceptedTaxon.getName());
+        newAcceptedTaxonHomotypicalgroup = HibernateProxyHelper.deproxy(newAcceptedTaxonHomotypicalgroup, HomotypicalGroup.class);
+        TaxonNameBase newAcceptedTaxonName = HibernateProxyHelper.deproxy(newAcceptedTaxon.getName(), TaxonNameBase.class);
         // Move Synonym Relations to new Taxon
         SynonymRelationship synonmyRelationship = newAcceptedTaxon.addSynonymName(synonymName,
                 synonymRelationshipType, citation, citationMicroReference);
@@ -149,7 +153,7 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
         for(SynonymRelationship synRelation : oldTaxon.getSynonymRelations()){
             SynonymRelationshipType srt;
             if(synRelation.getSynonym().getName().getHomotypicalGroup()!= null
-                    && synRelation.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxon.getName().getHomotypicalGroup())) {
+                    && synRelation.getSynonym().getName().getHomotypicalGroup().equals(newAcceptedTaxonName.getHomotypicalGroup())) {
                 srt = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
             } else if(synRelation.getType() != null && synRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())) {
                if (synonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
@@ -179,7 +183,11 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
 
         // CHILD NODES
         if(oldTaxonNode.getChildNodes() != null && oldTaxonNode.getChildNodes().size() != 0){
-            for(TaxonNode childNode : oldTaxonNode.getChildNodes()){
+               List<TaxonNode> childNodes = new ArrayList<TaxonNode>();
+               for (TaxonNode childNode : oldTaxonNode.getChildNodes()){
+                       childNodes.add(childNode);
+               }
+            for(TaxonNode childNode :childNodes){
                 newAcceptedTaxonNode.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference()); // childNode.getSynonymToBeUsed()
             }
         }
@@ -216,25 +224,62 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
             String message = "Description copied from former accepted taxon: %s (Old title: %s)";
             message = String.format(message, oldTaxon.getTitleCache(), description.getTitleCache());
             description.setTitleCache(message, true);
+            //oldTaxon.removeDescription(description, false);
             newAcceptedTaxon.addDescription(description);
         }
+        oldTaxon.clearDescriptions();
+
         taxonService.update(newAcceptedTaxon);
+
+        taxonService.update(oldTaxon);
+
         TaxonDeletionConfigurator conf = new TaxonDeletionConfigurator();
         conf.setDeleteSynonymsIfPossible(false);
-        List<String> deleteMessages = taxonService.isDeletable(oldTaxon, conf);
-//        conf.setDeleteNameIfPossible(false);
-        DeleteResult result;
-        if (deleteMessages.isEmpty()){
-                result = taxonService.deleteTaxon(oldTaxon, conf, null);
+        DeleteResult result = taxonService.isDeletable(oldTaxon, conf);
+        conf.setDeleteNameIfPossible(false);
+
+        if (result.isOk()){
+                result = taxonService.deleteTaxon(oldTaxon.getUuid(), conf, classification.getUuid());
         }else{
+               result.setStatus(Status.OK);
                TaxonNodeDeletionConfigurator config = new TaxonNodeDeletionConfigurator();
-               config.setDeleteTaxon(false);
+               config.setDeleteElement(false);
                conf.setTaxonNodeConfig(config);
-               result = deleteTaxonNode(oldTaxonNode, conf);
+               result.includeResult(deleteTaxonNode(oldTaxonNode, conf));
         }
+        result.addUpdatedObject(newAcceptedTaxon);
+        result.addUpdatedObject(oldTaxon);
 
         //oldTaxonNode.delete();
-        return synonmyRelationship.getSynonym();
+        return result;
+    }
+
+
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#makeTaxonNodeASynonymOfAnotherTaxonNode(java.util.UUID, java.util.UUID, java.util.UUID, java.util.UUID, java.lang.String)
+     */
+    @Override
+    @Transactional(readOnly = false)
+    public UpdateResult makeTaxonNodeASynonymOfAnotherTaxonNode(UUID oldTaxonNodeUuid,
+            UUID newAcceptedTaxonNodeUUID,
+            SynonymRelationshipType synonymRelationshipType,
+            Reference citation,
+            String citationMicroReference) {
+
+        TaxonNode oldTaxonNode = dao.load(oldTaxonNodeUuid);
+        TaxonNode oldTaxonParentNode = oldTaxonNode.getParent();
+        TaxonNode newTaxonNode = dao.load(newAcceptedTaxonNodeUUID);
+
+        UpdateResult result = makeTaxonNodeASynonymOfAnotherTaxonNode(oldTaxonNode,
+                newTaxonNode,
+                synonymRelationshipType,
+                citation,
+                citationMicroReference);
+        result.addUpdatedCdmId(new CdmEntityIdentifier(oldTaxonParentNode.getId(), TaxonNode.class));
+        result.addUpdatedCdmId(new CdmEntityIdentifier(newTaxonNode.getId(), TaxonNode.class));
+        result.setCdmEntity(oldTaxonParentNode);
+        return result;
     }
 
     /* (non-Javadoc)
@@ -242,150 +287,206 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
      */
     @Override
     @Transactional(readOnly = false)
-    public DeleteResult deleteTaxonNodes(Set<ITaxonTreeNode> nodes, TaxonDeletionConfigurator config) {
+    public DeleteResult deleteTaxonNodes(List<TaxonNode> list, TaxonDeletionConfigurator config) {
+
         if (config == null){
                config = new TaxonDeletionConfigurator();
         }
         DeleteResult result = new DeleteResult();
         List<UUID> deletedUUIDs = new ArrayList<UUID>();
         Classification classification = null;
-        for (ITaxonTreeNode treeNode:nodes){
+        List<TaxonNode> taxonNodes = new ArrayList<TaxonNode>(list);
+        for (TaxonNode treeNode:taxonNodes){
                if (treeNode != null){
-                       if (treeNode instanceof TaxonNode){
-                               TaxonNode taxonNode;
-                           taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
-
-                               //check whether the node has children or the children are already deleted
-                           if(taxonNode.hasChildNodes()){
-                               Set<ITaxonTreeNode> children = new HashSet<ITaxonTreeNode> ();
-                               List<TaxonNode> childNodesList = taxonNode.getChildNodes();
-                                       children.addAll(childNodesList);
-                                       int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
-                                       boolean childHandling = (compare == 0)? true: false;
-                               if (childHandling){
-                                       boolean changeDeleteTaxon = false;
-                                       if (!config.getTaxonNodeConfig().isDeleteTaxon()){
-                                               config.getTaxonNodeConfig().setDeleteTaxon(true);
-                                               changeDeleteTaxon = true;
-                                       }
-                                       DeleteResult resultNodes = deleteTaxonNodes(children, config);
-                                       if (!resultNodes.isOk()){
-                                result.addExceptions(resultNodes.getExceptions());
-                                result.setStatus(resultNodes.getStatus());
+
+                       TaxonNode taxonNode;
+                   taxonNode = HibernateProxyHelper.deproxy(treeNode, TaxonNode.class);
+                   TaxonNode parent = taxonNode.getParent();
+                       //check whether the node has children or the children are already deleted
+                   if(taxonNode.hasChildNodes()) {
+                       List<TaxonNode> children = new ArrayList<TaxonNode> ();
+                       List<TaxonNode> childNodesList = taxonNode.getChildNodes();
+                               children.addAll(childNodesList);
+                               int compare = config.getTaxonNodeConfig().getChildHandling().compareTo(ChildHandling.DELETE);
+                               boolean childHandling = (compare == 0)? true: false;
+                       if (childHandling){
+                               boolean changeDeleteTaxon = false;
+                               if (!config.getTaxonNodeConfig().isDeleteTaxon()){
+                                       config.getTaxonNodeConfig().setDeleteTaxon(true);
+                                       changeDeleteTaxon = true;
+                               }
+                               DeleteResult resultNodes = deleteTaxonNodes(children, config);
+                               if (!resultNodes.isOk()){
+                            result.addExceptions(resultNodes.getExceptions());
+                            result.setStatus(resultNodes.getStatus());
+                        }
+                               if (changeDeleteTaxon){
+                                       config.getTaxonNodeConfig().setDeleteTaxon(false);
+                               }
+
+                       } else {
+                               //move the children to the parent
+
+                               for (TaxonNode child: childNodesList){
+                                       parent.addChildNode(child, child.getReference(), child.getMicroReference());
+                               }
+
+                       }
+               }
+
+                   classification = taxonNode.getClassification();
+
+                   if (classification.getRootNode().equals(taxonNode)){
+                       classification.removeRootNode();
+                       classification = null;
+                   }else if (classification.getChildNodes().contains(taxonNode)){
+                       Taxon taxon = taxonNode.getTaxon();
+                       classification.deleteChildNode(taxonNode);
+
+                       //node is rootNode
+                       if (taxon != null){
+
+                               if (config.getTaxonNodeConfig().isDeleteTaxon()){
+                                   taxonService.saveOrUpdate(taxon);
+                                   saveOrUpdate(taxonNode);
+
+                                       TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
+                                       DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, classification.getUuid());
+                                       if (!resultTaxon.isOk()){
+                                result.addExceptions(resultTaxon.getExceptions());
+                                result.setStatus(resultTaxon.getStatus());
                             }
-                                       if (changeDeleteTaxon){
-                                               config.getTaxonNodeConfig().setDeleteTaxon(false);
-                                       }
-
-                               } else {
-                                       //move the children to the parent
-                                       TaxonNode parent = taxonNode.getParent();
-                                       for (TaxonNode child: childNodesList){
-                                               parent.addChildNode(child, child.getReference(), child.getMicroReference());
-                                       }
-
-                               }
-                       }
 
-                           classification = taxonNode.getClassification();
-
-                           if (classification.getRootNode().equals(taxonNode)){
-                               classification.removeRootNode();
-                               classification = null;
-                           }else if (classification.getChildNodes().contains(taxonNode)){
-                               Taxon taxon = taxonNode.getTaxon();
-                               classification.deleteChildNode(taxonNode);
-
-                               //node is rootNode
-                               if (taxon != null){
-
-                                       if (config.getTaxonNodeConfig().isDeleteTaxon()){
-                                           taxonService.saveOrUpdate(taxon);
-                                           saveOrUpdate(taxonNode);
-                                               TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
-                                               DeleteResult resultTaxon = taxonService.deleteTaxon(taxon, configNew, classification);
-                                               if (!resultTaxon.isOk()){
-                                       result.addExceptions(resultTaxon.getExceptions());
-                                       result.setStatus(resultTaxon.getStatus());
-                                   }
-
-                                       }
                                }
-                               classification = null;
-
-                           }else {
-                               classification = null;
-                               Taxon taxon = taxonNode.getTaxon();
-                               //node is rootNode
-                               if (taxon != null){
-                                       taxonNode.getTaxon().removeTaxonNode(taxonNode);
-                                       if (config.getTaxonNodeConfig().isDeleteTaxon()){
-                                               TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
-                                               saveOrUpdate(taxonNode);
-                                               taxonService.saveOrUpdate(taxon);
-                                               DeleteResult resultTaxon = taxonService.deleteTaxon(taxon, configNew, classification);
-                                if (!resultTaxon.isOk()){
-                                    result.addExceptions(resultTaxon.getExceptions());
-                                    result.setStatus(resultTaxon.getStatus());
-                                }
-                                       }
+                       }
+                       classification = null;
+
+                   } else {
+                       classification = null;
+                       Taxon taxon = taxonNode.getTaxon();
+                       taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
+                       if (taxon != null){
+                               taxon.removeTaxonNode(taxonNode);
+                               if (config.getTaxonNodeConfig().isDeleteTaxon()){
+                                       TaxonDeletionConfigurator configNew = new TaxonDeletionConfigurator();
+                                       saveOrUpdate(taxonNode);
+                                       taxonService.saveOrUpdate(taxon);
+                                       DeleteResult resultTaxon = taxonService.deleteTaxon(taxon.getUuid(), configNew, null);
+
+                            if (!resultTaxon.isOk()){
+                                result.addExceptions(resultTaxon.getExceptions());
+                                result.setStatus(resultTaxon.getStatus());
+                            }
                                }
+                       }
 
-                           }
-
-                           UUID uuid = dao.delete(taxonNode);
-                           logger.debug("Deleted node " +uuid.toString());
-                       }else {
-                               classification = (Classification) treeNode;
-
-                       }
+                   }
 
-                   //deletedUUIDs.add(treeNode.getUuid());
+                   result.addUpdatedObject(parent);
+                   if(result.getCdmEntity() == null){
+                       result.setCdmEntity(taxonNode);
+                }
+                   UUID uuid = dao.delete(taxonNode);
+                   logger.debug("Deleted node " +uuid.toString());
 
                }
         }
-        if (classification != null){
+        /*if (classification != null){
+            result.addUpdatedObject(classification);
                DeleteResult resultClassification = classService.delete(classification);
                 if (!resultClassification.isOk()){
                  result.addExceptions(resultClassification.getExceptions());
                  result.setStatus(resultClassification.getStatus());
              }
-        }
+        }*/
         return result;
 
     }
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#deleteTaxonNode(java.util.List)
-     */
+
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteTaxonNodes(Collection<UUID> nodeUuids, TaxonDeletionConfigurator config) {
+        List<TaxonNode> nodes = new ArrayList<TaxonNode>();
+        for(UUID nodeUuid : nodeUuids) {
+            nodes.add(dao.load(nodeUuid));
+        }
+        return deleteTaxonNodes(nodes, config);
+    }
+
+
+
+    @Override
+    @Transactional(readOnly = false)
+    public DeleteResult deleteTaxonNode(UUID nodeUUID, TaxonDeletionConfigurator config) {
+       TaxonNode node = HibernateProxyHelper.deproxy(dao.load(nodeUUID), TaxonNode.class);
+       return deleteTaxonNode(node, config);
+    }
+
     @Override
     @Transactional(readOnly = false)
     public DeleteResult deleteTaxonNode(TaxonNode node, TaxonDeletionConfigurator config) {
+
        Taxon taxon = (Taxon)HibernateProxyHelper.deproxy(node.getTaxon());
+       TaxonNode parent = HibernateProxyHelper.deproxy(node.getParent(), TaxonNode.class);
        if (config == null){
                config = new TaxonDeletionConfigurator();
        }
-       if (config.getTaxonNodeConfig().isDeleteTaxon()){
-               return taxonService.deleteTaxon(taxon, config, node.getClassification());
-       } else{
-               DeleteResult result = new DeleteResult();
-               boolean success = taxon.removeTaxonNode(node);
-               if (success){
-                       if (!dao.delete(node).equals(null)){
-                               return result;
-                       } else {
-                               result.setError();
-                               return result;
-                       }
-               }else{
-                       result.setError();
-                       result.addException(new Exception("The node can not be removed from the taxon."));
+       DeleteResult result = new DeleteResult();
+
+       if (config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.MOVE_TO_PARENT)){
+          Object[] children = node.getChildNodes().toArray();
+          TaxonNode childNode;
+          for (Object child: children){
+              childNode = (TaxonNode) child;
+              parent.addChildNode(childNode, childNode.getReference(), childNode.getMicroReference());
+          }
+       }else{
+           deleteTaxonNodes(node.getChildNodes(), config);
+       }
+
+       if (config.getTaxonNodeConfig().isDeleteTaxon() && (config.isDeleteInAllClassifications() || taxon.getTaxonNodes().size() == 1)){
+               result = taxonService.deleteTaxon(taxon.getUuid(), config, node.getClassification().getUuid());
+               result.addUpdatedObject(parent);
+               if (result.isOk()){
                        return result;
                }
+       } else {
+           result.addUpdatedObject(taxon);
+       }
 
+       result.setCdmEntity(node);
+       boolean success = taxon.removeTaxonNode(node);
+       dao.save(parent);
+       taxonService.saveOrUpdate(taxon);
+       result.addUpdatedObject(parent);
+
+       if (success){
+                       result.setStatus(Status.OK);
+                       parent = HibernateProxyHelper.deproxy(parent, TaxonNode.class);
+                       int index = parent.getChildNodes().indexOf(node);
+                       if (index > -1){
+                           parent.removeChild(index);
+                       }
+               if (!dao.delete(node, config.getTaxonNodeConfig().getChildHandling().equals(ChildHandling.DELETE)).equals(null)){
+                       return result;
+               } else {
+                       result.setError();
+                       return result;
+               }
+       }else{
+           if (dao.findByUuid(node.getUuid()) != null){
+                       result.setError();
+                       result.addException(new Exception("The node can not be removed from the taxon."));
+               }
+               return result;
        }
 
+
+
     }
 
+
     /* (non-Javadoc)
      * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#listAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification, int, int)
      */
@@ -394,14 +495,53 @@ public class TaxonNodeServiceImpl extends AnnotatableServiceBase<TaxonNode, ITax
         return dao.getTaxonOfAcceptedTaxaByClassification(classification, start, end);
     }
 
-    /* (non-Javadoc)
-     * @see eu.etaxonomy.cdm.api.service.ITaxonNodeService#countAllNodesForClassification(eu.etaxonomy.cdm.model.taxon.Classification)
-     */
     @Override
     public int countAllNodesForClassification(Classification classification) {
         return dao.countTaxonOfAcceptedTaxaByClassification(classification);
     }
 
+    @Override
+    @Transactional
+    public UpdateResult moveTaxonNode(UUID taxonNodeUuid, UUID targetNodeUuid, boolean isParent){
+        TaxonNode taxonNode = dao.load(taxonNodeUuid);
+       TaxonNode targetNode = dao.load(targetNodeUuid);
+       return moveTaxonNode(taxonNode, targetNode, isParent);
+    }
 
+    @Override
+    @Transactional
+    public UpdateResult moveTaxonNode(TaxonNode taxonNode, TaxonNode newParent, boolean isParent){
+        UpdateResult result = new UpdateResult();
+
+        Integer sortIndex;
+        if (isParent){
+
+            sortIndex = newParent.getChildNodes().size();
+        }else{
+            sortIndex = newParent.getSortIndex() +1;
+            newParent = newParent.getParent();
+        }
+        result.addUpdatedObject(newParent);
+        result.addUpdatedObject(taxonNode.getParent());
+        result.setCdmEntity(taxonNode);
+        newParent.addChildNode(taxonNode, sortIndex, taxonNode.getReference(),  taxonNode.getMicroReference());
+        dao.saveOrUpdate(newParent);
+
+        return result;
+    }
+
+
+
+    @Override
+    @Transactional
+    public UpdateResult moveTaxonNodes(Set<UUID> taxonNodeUuids, UUID newParentNodeUuid, boolean isParent){
+        UpdateResult result = new UpdateResult();
+        TaxonNode targetNode = dao.load(newParentNodeUuid);
+        for (UUID taxonNodeUuid: taxonNodeUuids){
+            TaxonNode taxonNode = dao.load(taxonNodeUuid);
+            result.includeResult(moveTaxonNode(taxonNode,targetNode, isParent));
+        }
+        return result;
+    }
 
 }