package de.terrestris.shoguncore.service;

import de.terrestris.shoguncore.dao.TreeNodeDao;
import de.terrestris.shoguncore.helper.IdHelper;
import de.terrestris.shoguncore.model.tree.TreeFolder;
import de.terrestris.shoguncore.model.tree.TreeNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * Service class for the {@link TreeNode} model.
 *
 * @author Nils Bühner
 * @see AbstractCrudService
 */
@Service("treeNodeService")
public class TreeNodeService<E extends TreeNode, D extends TreeNodeDao<E>> extends
    PermissionAwareCrudService<E, D> {

    /**
     * Default constructor, which calls the type-constructor
     */
    @SuppressWarnings("unchecked")
    public TreeNodeService() {
        this((Class<E>) TreeNode.class);
    }

    /**
     * Constructor that sets the concrete entity class for the service.
     * Subclasses MUST call this constructor.
     */
    protected TreeNodeService(Class<E> entityClass) {
        super(entityClass);
    }

    /**
     * This unproxies and eagerly fetches the whole node/tree and detaches it
     * from the hibernate session before persisting a new "clone" instance in the database.
     * In case of a TreeFolder, each child node will also be re-persisted (as a new database entry).
     *
     * @param node
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    @SuppressWarnings("unchecked")
    public E cloneAndPersistTreeNode(E node) throws Exception {

        if (node == null) {
            throw new Exception("Node to clone must not be null.");
        }

        // unproxy the node to be sure that everything (on top level) is loaded eagerly
        // before we continue to care about possible child notes and persistance
        node = dao.unproxy(node);

        if (node instanceof TreeFolder) {
            List<E> children = (List<E>) ((TreeFolder) node).getChildren();
            List<E> clonedChildren = new ArrayList<>();
            for (E childNode : children) {
                // recursive call for all children
                clonedChildren.add(cloneAndPersistTreeNode(childNode));
            }
            ((TreeFolder) node).setChildren((List<TreeNode>) clonedChildren);
        }

        // detach the clone from the hibernate session to persist it as a new instance in the next step
        dao.evict(node);

        // set id to null to persist a new instance afterwards
        IdHelper.setIdOnPersistentObject(node, null);

        // persist the same object as a new entry in database
        dao.saveOrUpdate(node);

        return node;
    }

    /**
     * We have to use {@link Qualifier} to define the correct dao here.
     * Otherwise, spring can not decide which dao has to be autowired here
     * as there are multiple candidates.
     */
    @Override
    @Autowired
    @Qualifier("treeNodeDao")
    public void setDao(D dao) {
        this.dao = dao;
    }
}

@@ -130,24 +130,186 @@
 r.IdHelper;%0A
+import de.terrestris.shoguncore.model.User;%0Aimport de.terrestris.shoguncore.model.UserGroup;%0Aimport de.terrestris.shoguncore.model.security.PermissionCollection;%0A
 import de.te
@@ -599,40 +599,9 @@
 til.
-ArrayList;%0Aimport java.util.List
+*
 ;%0A%0A/
@@ -1681,43 +1681,8 @@
  */%0A
-    @SuppressWarnings(%22unchecked%22)%0A
     
@@ -1741,16 +1741,187 @@
 ption %7B%0A
+        return cloneAndPersistTreeNode(node, true, new ArrayList%3C%3E());%0A    %7D%0A%0A    private E cloneAndPersistTreeNode(E node, boolean root, List%3CE%3E nodes) throws Exception %7B
 %0A       
@@ -2218,24 +2218,842 @@
 proxy(node);
+%0A        HashMap%3CUser, PermissionCollection%3E userPermissions = new HashMap%3C%3E();%0A        node.getUserPermissions().forEach((user, coll) -%3E %7B%0A            PermissionCollection collection = new PermissionCollection();%0A            collection.setPermissions(new HashSet%3C%3E(coll.getPermissions()));%0A            userPermissions.put(user, collection);%0A        %7D);%0A        node.setUserPermissions(userPermissions);%0A        HashMap%3CUserGroup, PermissionCollection%3E groupPermissions = new HashMap%3C%3E();%0A        node.getGroupPermissions().forEach((group, coll) -%3E %7B%0A            PermissionCollection collection = new PermissionCollection();%0A            collection.setPermissions(new HashSet%3C%3E(coll.getPermissions()));%0A            groupPermissions.put(group, collection);%0A        %7D);%0A        node.setGroupPermissions(groupPermissions);
 %0A%0A        if
@@ -3330,27 +3330,18 @@
     
-clonedChildren.add(
+E child = 
 clon
@@ -3369,17 +3369,131 @@
 hildNode
-)
+, false, nodes);%0A                child.setParentFolder((TreeFolder) node);%0A                clonedChildren.add(child
 );%0A     
@@ -3834,24 +3834,74 @@
 de, null);%0A%0A
+        nodes.add(node);%0A%0A        if (root) %7B%0A    
         // p
@@ -3958,20 +3958,79 @@
         
+    Collections.reverse(nodes);%0A            nodes.forEach(
 dao
-.
+::
 saveOrUp
@@ -4033,23 +4033,28 @@
 OrUpdate
-(node);
+);%0A        %7D
 %0A%0A      

Fix copying of applications (#385)